package com.example.wan1.base.mvp;

import android.content.Context;
import android.util.Log;

import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/***
 * 创建时间：2020/4/26 20:36
 * 创建人：10850
 * 功能描述：这里可以不用添加IBasePreesenter接口
 * 因为IBasePreesenter里面的两个方法，一个绑定(attach)view，另外一个解绑(detach),可以直接在BasePresenter.class中实现
 * 多加一个接口的话，觉得会更繁琐。本来使用MVP为了解耦多了好多类。。能少一个是一个
 *
 *
 * 使用动态代理模式设计basePresenter的初忠：
 * 因为在使用mvp模式开发中，会遇到一些问题：
 * 比如：activity持有presenter的引用，presenter持有view的引用 ，这就导致几个问题，
 * 1.当activity销毁后，由于p持有activity的引用 导致activity无法释放，最终会引用内存泄漏
 * <p>
 * 2.p层处理完逻辑，调用v层来处理UI，怎么拿到V层的引用？
 * <p>
 * 3.请求网络时，网络不太好，在这个时候用户没等到请求完成退出该页面，等获取数据成功之后再拿V的引用 ，
 * 这个时候view 有可能被销毁，v层的引用为空
 *
 * 注意：presenter可以持有view和model的引用，主要是和view的绑定和解绑。model的引用可以不要，也就是public abstract class BasePresenter<V extends IBaseView>
 *
 *
 * 再度优化：我们每次在presenter中都要实例化model，可以通过反射的方法，省掉重复的代码
 * 把IBaseModel换成BaseModel
 *
 * 思考：能不能把model给去掉？
 * 我觉得可以。是可以去掉，但是每次都要new DataClient的话，这个怎么解决？
 *
 * 如果在构造方法里 加DataClient的话，很麻烦。因为继承这个BasePresenter的都要实现其构造方法，即使什么也不做
 */
@SuppressWarnings("unchecked")
public abstract class BasePresenter<V extends IBaseView> {

    private V mProxyView;
    /**
     * 解决第一个问题
     * <p>
     * 弱引用, 防止内存泄漏
     */
    private WeakReference<V> weakReference;

    /**
     * 绑定View
     * 关联V层和P层
     */
    public void attachView(V view) {
        Log.i("zxd", "attachView: " + view.getClass().getName());
        weakReference = new WeakReference<>(view);
        mProxyView = (V) Proxy.newProxyInstance(
                view.getClass().getClassLoader(),
                view.getClass().getInterfaces(),
                new MvpViewHandler(weakReference.get()));
    }

    /**
     * 解绑View
     * 断开V层和P层
     * 在Acitivity的onDestory()中调用
     */
    public void detachView() {
        if (isViewAttached()) {
            weakReference.clear();
            weakReference = null;
        }
    }

    /**
     * 是否与View建立连接
     */
    protected boolean isViewAttached() {
        return weakReference != null && weakReference.get() != null;
    }

    /**
     * 解决第二个问题
     */
    protected V getView() {
        return mProxyView;
    }

    protected Context getContext() {
        return getView().getContext();
    }

    /**
     * 初始化方法
     */
    public abstract void start();

    /**
     * View代理类  防止 页面关闭P异步操作调用V 方法 空指针问题
     */
    private class MvpViewHandler implements InvocationHandler {

        private IBaseView mvpView;

        MvpViewHandler(IBaseView mvpView) {
            this.mvpView = mvpView;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //解决第三个问题，如果V层没被销毁, 执行V层的方法.
            //如果V层没被销毁, 执行V层的方法.
            if (isViewAttached()) {
                return method.invoke(mvpView, args);
            } //P层不需要关注V层的返回值
            return null;
        }
    }
}